/*
 * @Author       : xiangmin
 * @File         : axios 简单TS泛型封装
 * @Date         : 2022-11-19 12:16:16
 * @LastEditors  : xiangmin
 * @LastEditTime : 2023-11-17 11:04:50
 */
import axios, { type AxiosError, type AxiosRequestConfig } from 'axios'

declare module 'axios' {
	interface AxiosRequestConfig {
		abort?: boolean
		toast?: boolean
	}
}

export type Config = Omit<AxiosRequestConfig, 'url' | 'params' | 'data' | 'get' | 'post'>

export interface RequestConfig {
	url: string
	params?: Record<string, any>
	config?: Config
}

interface ResponseData<T> {
	status: number
	toast: string
	data: T
	success: boolean
}

const AxiosInstance = axios.create({
	timeout: 20000,
	withCredentials: true,
	timeoutErrorMessage: '请求超时，请重试!'
})

// 添加请求拦截器
const abortMap = new Map()
AxiosInstance.interceptors.request.use(
	config => {
		// 打断掉重复请求
		if (config.abort) {
			const controller = new AbortController()
			config.signal = controller.signal
			const key = config.url
			if (abortMap.has(key)) {
				abortMap.get(key).abort()
				abortMap.delete(key)
			}
			abortMap.set(key, controller)
		}
		return config
	},
	error => Promise.reject(error)
)

const HttpErrorCode = {
	400: '请求参数错误',
	401: '未授权，无法访问',
	403: '服务器拒绝访问',
	404: '请求地址出错',
	405: '请求方法错误',
	408: '请求超时',
	500: '服务器内部错误',
	501: '服务未实现',
	502: '网关错误',
	503: '服务不可用',
	504: '网关超时'
}
AxiosInstance.interceptors.response.use(
	response => response,
	// 服务器状态码不是200的情况，可封装404， 500等逻辑等逻辑
	(error: AxiosError) => {
		const code = error.code
		const errorMessage = HttpErrorCode[error.response?.status as number] || error.message
		if (errorMessage && code !== 'ERR_CANCELED') {
			message.error(`${code}: ${errorMessage}`)
		}
		if (code === 'ERR_CANCELED') {
			// eslint-disable-next-line
			console.warn(`${error.config?.url}：🤪重复请求取消，不用惊慌😤`)
			return Promise.reject(null)
		}
		return Promise.reject(error)
	}
)

function get<T>({ url, params = {}, config = {} }: RequestConfig) {
	config = { abort: true, toast: true, ...config }
	return AxiosInstance.get<ResponseData<T>>(url, { params, ...config })
		.then(response => {
			if (!response.data.success) {
				config.toast && message.error(response?.data?.toast)
				return Promise.reject(response.data)
			}
			return response.data.data
		})
		.catch(error => Promise.reject(error))
}

function post<T>({ url, params = {}, config = {} }: RequestConfig) {
	config = { abort: true, toast: true, ...config }
	return AxiosInstance.post<ResponseData<T>>(url, params, config)
		.then(response => {
			if (response.data?.status !== 0) {
				config.toast && message.error(response?.data?.toast)
				return Promise.reject(response)
			}
			return response.data?.data
		})
		.catch(error => Promise.reject(error))
}

export { get, post }
